package main

import (
	"encoding/json"
	"fmt"
	"errors"
	"github.com/hyperledger/fabric-contract-api-go/contractapi"
	"github.com/hyperledger/fabric-chaincode-go/shim"
    "github.com/hyperledger/fabric-protos-go/peer"
	"strconv"
)

// Contract structure
type Contract struct {
	ContractID   int     `json:"contractId"`
	CompanyID    string  `json:"companyId"`
	CompanyName  string  `json:"companyName"`
	Year         string  `json:"year"`
	Month        string  `json:"month"`
	Amount       float64 `json:"amount"`
	Context      string  `json:"context"`
}

// Company structure
type Company struct {
	CompanyID   int    `json:"companyId"`
	CompanyName string `json:"companyName"`
	Industry    string `json:"industry"`
	Province    string `json:"province"`
}

// SimpleChaincode defines the Smart Contract structure
type SimpleChaincode struct {
}

// Init method is called when the chaincode is instantiated
func (s *SimpleChaincode) Init(stub shim.ChaincodeStubInterface) peer.Response {
	fmt.Println("初始化合同链码")
	return shim.Success(nil)
}

// Invoke method is called when a transaction is submitted to the chaincode
func (s *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface) peer.Response {
	fmt.Println("调用函数")
	function, args := stub.GetFunctionAndParameters()
	switch function {
	case "addContract":
		return s.addContract(ctx, args)
	case "adCompany":
		return s.adCompany(ctx, args)
	case "updateContractById":
		return s.updateContractById(ctx, args)
	case "updateCompanyById":
		return s.updateCompanyById(ctx, args)
	case "getContractById":
		return s.getContractById(ctx, args)
	case "getCompanyById":
		return s.getCompanyById(ctx, args)
	case "deleteContractById":
		return s.deleteContractById(ctx, args)
	default:
		return nil, fmt.Errorf("Invalid function name. Available functions are: addContract, adCompany, updateContractById, updateCompanyById, getContractById, getCompanyById, deleteContractById.")
	}
}

// Add a contract
func (s *SimpleChaincode) addContract(stub shim.ChaincodeStubInterface, args []string) peer.Response {
	if len(args) != 7 {
		return nil, fmt.Errorf("Incorrect number of arguments. Expected 7 arguments: contractId, contractTitle, contractDescription, contractType, contractHash, firstPartyId, secondPartyId")
	}

	contractID := args[0]
	contract := Contract{
		ContractID:  strconv.Atoi(contractID),
		CompanyID:   args[1],
		CompanyName: args[2],
		Year:        args[3],
		Month:       args[4],
		Amount:      strconv.Atoi(args[5]),
		Context:     args[6],
	}

	contractBytes, err := json.Marshal(contract)
	if err != nil {
		return nil, fmt.Errorf("Failed to marshal contract: %v", err)
	}

	err = ctx.GetStub().PutState("contract_"+contractID, contractBytes)
	if err != nil {
		return nil, fmt.Errorf("Failed to add contract: %v", err)
	}

	return contractBytes, nil
}

// Add a company
func (s *SimpleChaincode) adCompany(ctx contractapi.TransactionContextInterface, args []string) ([]byte, error) {
	if len(args) != 4 {
		return nil, fmt.Errorf("Incorrect number of arguments. Expected 4 arguments: companyId, companyName, industry, province")
	}

	companyID := args[0]
	company := Company{
		CompanyID:   strconv.Atoi(companyID),
		CompanyName: args[1],
		Industry:    args[2],
		Province:    args[3],
	}

	companyBytes, err := json.Marshal(company)
	if err != nil {
		return nil, fmt.Errorf("Failed to marshal company: %v", err)
	}

	err = ctx.GetStub().PutState("company_"+companyID, companyBytes)
	if err != nil {
		return nil, fmt.Errorf("Failed to add company: %v", err)
	}

	return companyBytes, nil
}

// Update a contract by ID
func (s *SimpleChaincode) updateContractById(ctx contractapi.TransactionContextInterface, args []string) ([]byte, error) {
	if len(args) != 7 {
		return nil, fmt.Errorf("Incorrect number of arguments. Expected 7 arguments: contractId, contractTitle, contractDescription, contractType, contractHash, firstPartyId, secondPartyId")
	}

	contractID := args[0]
	contract := Contract{
		ContractID:  strconv.Atoi(contractID),
		CompanyID:   args[1],
		CompanyName: args[2],
		Year:        args[3],
		Month:       args[4],
		Amount:      strconv.Atoi(args[5]),
		Context:     args[6],
	}

	contractBytes, err := json.Marshal(contract)
	if err != nil {
		return nil, fmt.Errorf("Failed to marshal contract: %v", err)
	}

	err = ctx.GetStub().PutState("contract_"+contractID, contractBytes)
	if err != nil {
		return nil, fmt.Errorf("Failed to update contract: %v", err)
	}

	return contractBytes, nil
}

// Update a company by ID
func (s *SimpleChaincode) updateCompanyById(ctx contractapi.TransactionContextInterface, args []string) ([]byte, error) {
	if len(args) != 4 {
		return nil, fmt.Errorf("Incorrect number of arguments. Expected 4 arguments: companyId, companyName, industry, province")
	}

	companyID := args[0]
	company := Company{
		CompanyID:   strconv.Atoi(companyID),
		CompanyName: args[1],
		Industry:    args[2],
		Province:    args[3],
	}

	companyBytes, err := json.Marshal(company)
	if err != nil {
		return nil, fmt.Errorf("Failed to marshal company: %v", err)
	}

	err = ctx.GetStub().PutState("company_"+companyID, companyBytes)
	if err != nil {
		return nil, fmt.Errorf("Failed to update company: %v", err)
	}

	return companyBytes, nil
}

// Get contract by ID
func (s *SimpleChaincode) getContractById(ctx contractapi.TransactionContextInterface, args []string) ([]byte, error) {
	if len(args) != 1 {
		return nil, fmt.Errorf("Incorrect number of arguments. Expected 1 argument: contractId")
	}

	contractID := args[0]
	contractBytes, err := ctx.GetStub().GetState("contract_" + contractID)
	if err != nil {
		return nil, fmt.Errorf("Failed to read contract from world state: %v", err)
	}

	if contractBytes == nil {
		return nil, fmt.Errorf("Contract with ID %s does not exist", contractID)
	}

	return contractBytes, nil
}

// Get company by ID
func (s *SimpleChaincode) getCompanyById(ctx contractapi.TransactionContextInterface, args []string) ([]byte, error) {
	if len(args) != 1 {
		return nil, fmt.Errorf("Incorrect number of arguments. Expected 1 argument: companyId")
	}

	companyID := args[0]
	companyBytes, err := ctx.GetStub().GetState("company_" + companyID)
	if err != nil {
		return nil, fmt.Errorf("Failed to read company from world state: %v", err)
	}

	if companyBytes == nil {
		return nil, fmt.Errorf("Company with ID %s does not exist", companyID)
	}

	return companyBytes, nil
}

// Delete contract by ID
func (s *SimpleChaincode) deleteContractById(ctx contractapi.TransactionContextInterface, args []string) ([]byte, error) {
	if len(args) != 1 {
		return nil, fmt.Errorf("Incorrect number of arguments. Expected 1 argument: contractId")
	}

	contractID := args[0]
	contractBytes, err := ctx.GetStub().GetState("contract_" + contractID)
	if err != nil {
		return nil, fmt.Errorf("Failed to read contract from world state: %v", err)
	}

	if contractBytes == nil {
		return nil, fmt.Errorf("Contract with ID %s does not exist", contractID)
	}

	err = ctx.GetStub().DelState("contract_" + contractID)
	if err != nil {
		return nil, fmt.Errorf("Failed to delete contract: %v", err)
	}

	return nil, nil
}

func main() {
	err := shim.Start(new(SimpleChainCode))
	if err != nil {
		fmt.Printf("创建合同链码时出错: %s", err)
	}
}
